////////////////////////////////////////////////
// -- DepthHUD Lite                           //
// by Hurricaaane (Ha3)                       //
//                                            //
// http://www.youtube.com/user/Hurricaaane    //
//--------------------------------------------//
// Virtual Scene                              //
////////////////////////////////////////////////

local RING_TEX_ID = surface.GetTextureID( "dhlite/rad_ring.vmt" )
local RING_MATFIX = 1.07
local DHLITE_CURRENT_VIEWDATA = nil
local DHLITE_CALC_SCREENPOS = nil

function dhlite:GetPinScale()
	return self.GetVar( "dhlite_regmod_size" ) / 256 * self.GetVar( "dhlite_regmod_pinscale" ) / 5
end

function dhlite:GetPin3DScale( )
	return self.GetVar( "dhlite_regmod_pinscale" ) / 5
end

function dhlite.HUDPaint()
	if not dhlite:IsEnabled() then return end
	
	
	if not dhlite.dat.view_data then
		dhlite.dat.view_data = {}
	end
	
	do
		dhlite:RecomEyemod()
		dhlite:OverwhelmEvaluate()
		
	end
	dhlite:DoRenderVirtualScene( dhlite.dat.view_data )

end

////////////////////////////////////////////////
////////////////////////////////////////////////

local DHLITE_LASTMODE = nil

function dhlite:EyemodEvaluate()
	local size = ScrH()
	self.dat.view_data.draww = size
	self.dat.view_data.drawh = size
	self.dat.view_data.drawx = ScrW() / 2 - size / 2
	self.dat.view_data.drawy = ScrH() / 2 - size / 2
	self.dat.view_data.foveval    = LocalPlayer():GetFOV()
	self.dat.view_data.bypass_distance = dhlite.GetVar("dhlite_global_finderdistance")
	
end

function dhlite:OverwhelmEvaluate()
	self.dat.view_data.draww = ScrW()
	self.dat.view_data.drawh = ScrH()
	self.dat.view_data.drawx = 0
	self.dat.view_data.drawy = 0
	self.dat.view_data.foveval    = LocalPlayer():GetFOV()
	
end

function dhlite:RegularEvaluate()
	local size = dhlite.GetVar("dhlite_regmod_size")
	self.dat.view_data.draww = size
	self.dat.view_data.drawh = size
	self.dat.view_data.drawx = dhlite.GetVar("dhlite_regmod_xrel") * ScrW() - size / 2
	self.dat.view_data.drawy = dhlite.GetVar("dhlite_regmod_yrel") * ScrH() - size / 2
	self.dat.view_data.foveval    = dhlite.GetVar("dhlite_regmod_fov")
	self.dat.view_data.radiuseval = dhlite.GetVar("dhlite_regmod_radius")
	self.dat.view_data.bypass_distance = dhlite.GetVar("dhlite_global_finderdistance")
	
end

function dhlite:RecomEyemod()
	if DHLITE_LASTMODE == "EYEMOD" then return end
	DHLITE_LASTMODE = "EYEMOD"
	
	self.dat.ang_before_pos = true
	self.dat.view_data.referencepos_func = function( viewData )
		return EyePos()
		
	end
	self.dat.view_data.referenceang_func = function( viewData )
		return (sharpeye_focus and sharpeye_focus.GetSmoothedViewAngles and sharpeye_focus:GetSmoothedViewAngles()) or EyeAngles()
		
	end
	self.dat.view_data.pos_func = function( viewData )
		return EyePos()
		
	end
	self.dat.view_data.ang_func = function( viewData )
		return (sharpeye_focus and sharpeye_focus.GetSmoothedViewAngles and sharpeye_focus:GetSmoothedViewAngles()) or EyeAngles()
		
	end
	
	self.dat.view_data.referencepos = nil
	self.dat.view_data.referenceang = nil
	self.dat.view_data.pos = nil
	self.dat.view_data.ang = nil

	
	self.dat.view_data.radiuseval_func = function( viewData ) return nil end
	self.dat.view_data.foveval_func    = function( viewData ) return nil end
	self.dat.view_data.radiuseval = 2048
	self.dat.view_data.foveval = 10
	
	self.dat.view_data.drawx  = 0
	self.dat.view_data.drawy  = 0
	self.dat.view_data.draww  = 0
	self.dat.view_data.drawh  = 0
	
	self.dat.view_data.margin = 2^0.5
	
end

function dhlite:RecomRegular()
	if DHLITE_LASTMODE == "REGULAR" then return end
	DHLITE_LASTMODE = "REGULAR"
	
	self.dat.ang_before_pos = true
	self.dat.view_data.referencepos_func = function( viewData )
		return EyePos()
		
	end
	self.dat.view_data.referenceang_func = function( viewData )
		return EyeAngles()
		
	end
	self.dat.view_data.pos_func = function( viewData )
		local dist = viewData.radiuseval / math.tan( math.rad( viewData.foveval / 2 ) )
		return viewData.referencepos - viewData.ang:Forward() * dist
		
	end
	self.dat.view_data.ang_func = function( viewData )
		return Angle( dhlite.GetVar("dhlite_regmod_angle") + (dhlite.GetVar("dhlite_regmod_pitchdyn") / 10) * viewData.referenceang.p, viewData.referenceang.y, 0 )
	end
	
	self.dat.view_data.referencepos = nil
	self.dat.view_data.referenceang = nil
	self.dat.view_data.pos = nil
	self.dat.view_data.ang = nil

	
	self.dat.view_data.radiuseval_func = function( viewData ) return nil end
	self.dat.view_data.foveval_func    = function( viewData ) return nil end
	self.dat.view_data.radiuseval = 512
	self.dat.view_data.foveval = 10
	
	self.dat.view_data.drawx  = 0
	self.dat.view_data.drawy  = 0
	self.dat.view_data.draww  = 0
	self.dat.view_data.drawh  = 0
	
	self.dat.view_data.margin = 2^0.5
	
end

////////////////////////////////////////////////
////////////////////////////////////////////////

function dhlite:GetCurrentViewData()
	return DHLITE_CURRENT_VIEWDATA
end

function dhlite:DoRenderVirtualScene( viewData )
	DHLITE_CURRENT_VIEWDATA = viewData
	
	-- We need these because Vector:ToScreen() uses the viewport as a reference, but uses the raw Screen sizes from 0 to Screen Size as range of values no matter where the viewport is or which size the viewport is
	viewData.raw_scrw = ScrW()
	viewData.raw_scrh = ScrH()
	
	local xDraw, yDraw    = viewData.drawx, viewData.drawy
	local iWidth, iHeight = viewData.draww, viewData.drawh
	
	-- Calculate actual values
	viewData.referencepos = viewData.referencepos_func(viewData) or viewData.referencepos
	viewData.referenceang = viewData.referenceang_func(viewData) or viewData.referenceang
	
	if self.dat.ang_before_pos then
		viewData.ang          = viewData.ang_func(viewData)          or viewData.ang
		viewData.pos          = viewData.pos_func(viewData)          or viewData.pos
		
	else
		viewData.pos          = viewData.pos_func(viewData)          or viewData.pos
		viewData.ang          = viewData.ang_func(viewData)          or viewData.ang
	
	end
	
	viewData.radiuseval   = viewData.radiuseval_func(viewData)   or viewData.radiuseval
	viewData.foveval      = viewData.foveval_func(viewData)      or viewData.foveval
	
	viewData.baseratio = math.tan( math.rad( viewData.foveval / 2 / viewData.margin ) )
	viewData.baseratio_nomargin = math.tan( math.rad( viewData.foveval / 2 ) )
	
	--self:DoFindComputeEnts( viewData )
	
	/*render.ClearStencil()
	render.SetStencilEnable( true )
	render.SetStencilFailOperation( STENCILOPERATION_KEEP )
	render.SetStencilPassOperation( STENCILOPERATION_REPLACE )
	render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS )
	render.SetStencilReferenceValue( 1 )*/
	
	---- Background circle
	surface.SetDrawColor( self:Util_GetVarColorVariadic( "dhlite_uidesign_backcolor") )
	surface.SetTexture( nil )
	//surface.DrawPoly( self:CalcCircle( 36, iWidth / 2, viewData.drawx, viewData.drawy ) )
	surface.DrawRect( xDraw, yDraw, iWidth, iHeight )
	
	-- Operation : Keep (We don't want any stencil modification to happen after drawing the polygon).
	//render.SetStencilPassOperation( STENCILOPERATION_KEEP )
	
	---- Undercontents
	
	-- Comparaison : Equal : We want all operations to be drawn on the circle.
	//render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL )
	
	cam.Start3D( viewData.pos, viewData.ang, viewData.foveval/*, xDraw, yDraw, iWidth, iHeight*/ )
		local bOkayFirst, strErrFirst = pcall( self.DoCameraMath, self, viewData )
		if bOkayFirst then
			local bOkay, strErr = pcall( self.DoCameraUnderScene, self, viewData )
			if not bOkay then ErrorNoHalt( ">> Dhlite ERROR : " .. strErr ) end
			
		end
		
	cam.End3D()
	if not bOkayFirst then ErrorNoHalt( ">> Dhlite ERROR : " .. strErrFirst )	end
	
	--[[---- Drawing the ring.

	-- Compare : We want it only to draw no matter what
	//render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS )
	
	local iSurfWidth, iSurfHeight    = iWidth * RING_MATFIX, iHeight * RING_MATFIX
	local iDrawXCenter, iDrawYCenter = xDraw + iWidth / 2, yDraw + iHeight / 2
	surface.SetDrawColor( self:Util_GetVarColorVariadic( "dhlite_uidesign_ringcolor") )
	surface.SetTexture( RING_TEX_ID )
	surface.DrawTexturedRectRotated( iDrawXCenter, iDrawYCenter, iSurfWidth, iSurfHeight, 0)
	
	---- Preparing Overcontents
	if bOkayFirst then
		-- Comparaison : Equal : We want all operations to be drawn on the circle.
	//render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL )
		
		---- Overcontents
		cam.Start3D( viewData.pos, viewData.ang, viewData.foveval /*, xDraw, yDraw, iWidth, iHeight*/ )
			local bOkay, strErr = pcall( self.DoCameraOverScene, self, viewData )
			
		cam.End3D()
		if not bOkay then ErrorNoHalt( ">> Dhlite ERROR : " .. strErr ) end
		
	end]]--
	
	//render.SetStencilEnable( false )
	
end

////////////////////////////////////////////////
////////////////////////////////////////////////

function dhlite:ConvertPosToScreen( vPos, fAlterX, fAlterY )
	DHLITE_CALC_SCREENPOS = vPos:ToScreen()
	DHLITE_CALC_SCREENPOS.x = (DHLITE_CALC_SCREENPOS.x / DHLITE_CURRENT_VIEWDATA.raw_scrw + (fAlterX or 0) / 2) * DHLITE_CURRENT_VIEWDATA.draww
	DHLITE_CALC_SCREENPOS.y = (DHLITE_CALC_SCREENPOS.y / DHLITE_CURRENT_VIEWDATA.raw_scrh + (fAlterY or 0) / 2) * DHLITE_CURRENT_VIEWDATA.drawh
	
	return DHLITE_CALC_SCREENPOS.x, DHLITE_CALC_SCREENPOS.y
	
end

function dhlite:ConvertPosToRelative( vPos )
	DHLITE_CALC_SCREENPOS = vPos:ToScreen()
	DHLITE_CALC_SCREENPOS.x = (DHLITE_CALC_SCREENPOS.x / DHLITE_CURRENT_VIEWDATA.raw_scrw) * 2 - 1
	DHLITE_CALC_SCREENPOS.y = (DHLITE_CALC_SCREENPOS.y / DHLITE_CURRENT_VIEWDATA.raw_scrh) * 2 - 1
	
	return DHLITE_CALC_SCREENPOS.x, DHLITE_CALC_SCREENPOS.y
	
end

function dhlite:ConvertRelativeToScreen( fAlterX, fAlterY )
	local x,y = (fAlterX + 1) / 2 * DHLITE_CURRENT_VIEWDATA.draww, (fAlterY + 1) / 2 * DHLITE_CURRENT_VIEWDATA.drawh
	
	return x, y
	
end


////////////////////////////////////////////////
////////////////////////////////////////////////

local DHLITE_CAMERA_FIX = 1
local DHLITE_CIRCLE_POLYGON = {}
local DHLITE_CIRCLE_RES = -1
local DHLITE_CIRCLE_RADIUS = -1
local DHLITE_CIRCLE_IDX = -1
local DHLITE_CIRCLE_IDY = -1


// CalcCircle should use viewdata for multiplicity ?
function dhlite:CalcCircle( iRes, iRadius, iDrawX, iDrawY )
	if DHLITE_CIRCLE_RES == iRes and DHLITE_CIRCLE_RADIUS == iRadius and DHLITE_CIRCLE_IDX == iDrawX and DHLITE_CIRCLE_IDY == iDrawY then return DHLITE_CIRCLE_POLYGON end
	
	DHLITE_CIRCLE_RES = iRes
	DHLITE_CIRCLE_RADIUS = iRadius
	DHLITE_CIRCLE_IDX = iDrawX
	DHLITE_CIRCLE_IDY = iDrawY
	
	for i = 1, iRes do
		if not DHLITE_CIRCLE_POLYGON[i] then
			DHLITE_CIRCLE_POLYGON[i] = {}
			
		end
		
		DHLITE_CIRCLE_POLYGON[i]["x"] = math.cos( math.rad( i / iRes * 360 ) ) * iRadius
		DHLITE_CIRCLE_POLYGON[i]["y"] = math.sin( math.rad( i / iRes * 360 ) ) * iRadius
		DHLITE_CIRCLE_POLYGON[i]["u"] = (iRadius - DHLITE_CIRCLE_POLYGON[i]["x"]) / (2 * iRadius)
		DHLITE_CIRCLE_POLYGON[i]["v"] = (iRadius - DHLITE_CIRCLE_POLYGON[i]["y"]) / (2 * iRadius)

		DHLITE_CIRCLE_POLYGON[i]["x"] = iDrawX + iRadius + DHLITE_CIRCLE_POLYGON[i]["x"]
		DHLITE_CIRCLE_POLYGON[i]["y"] = iDrawY + iRadius + DHLITE_CIRCLE_POLYGON[i]["y"]

	end
	
	return DHLITE_CIRCLE_POLYGON
		
end

////////////////////////////////////////////////
////////////////////////////////////////////////

function dhlite:DoCameraUnderScene( viewData )
	self:DebugElementOps( 1, viewData )
	
	cam.Start2D()
		local bOkay, strErr = pcall( function()
		self:DebugElementOps( 2, viewData )
		
	end )
	cam.End2D()
	
	if not bOkay then ErrorNoHalt( ">> Dhlite ERROR : " .. strErr ) end
	
end

function dhlite:DoCameraOverScene( viewData )
	self:DebugElementOps( 3, viewData )
	
	cam.Start2D()
		local bOkay, strErr = pcall( function()
		self:DebugElementOps( 4, viewData )
		
	end )
	cam.End2D()
	
	if not bOkay then ErrorNoHalt( ">> Dhlite ERROR : " .. strErr ) end
	
end
